import { Global, Logger, LoggerService, Module } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
import * as dotenv from "dotenv";
import * as Joi from "joi";
import { TypeOrmModule } from "@nestjs/typeorm";
import { connectionParams } from "../ormconfig";
import { UserModule } from "@/modules/user/user.module";
import { RoleModule } from "@/modules/role/role.module";
import { APP_FILTER, APP_GUARD } from "@nestjs/core";
import { AuthModule } from "@/modules/auth/auth.module";
import { JwtAuthGuard } from "@/guard/jwt-auth.guard";
import { UserRoleModule } from "./modules/user-role/user-role.module";
import { SysConfigModule } from "./modules/sys-config/sys-config.module";
import { SysDictModule } from "./modules/sys-dict/sys-dict.module";
import { LogModule } from "./modules/log/log.module";
import { Log } from "@/modules/log/entities/log.entity";
import { ExceptionsFilter } from "@/filters/exceptions-filter";
import { HttpExceptionFilter } from "@/filters/http-exception.filter";
import { ScheduleModule } from "@nestjs/schedule";
import { TasksModule } from "@/schedule/tasks.module";
import { MenuModule } from "./modules/menu/menu.module";
import { RoleMenuModule } from "./modules/role-menu/role-menu.module";
import { ApiModule } from "./modules/api/api.module";
import { RoleApiModule } from "./modules/role-api/role-api.module";
import { UserSubuserModule } from "./modules/user-subuser/user-subuser.module";
import { OssModule } from "./modules/oss/oss.module";
import { ServeStaticModule, ServeStaticModuleOptions } from "@nestjs/serve-static";
import path from "path";

const envFilePath = `.env.${process.env.NODE_ENV || `development`}`;

const schema = Joi.object({
    NODE_ENV: Joi.string()
        .valid("development", "production", "test")
        .default("development"),
    DB_PORT: Joi.number().default(3306),
    DB_HOST: Joi.alternatives().try(Joi.string().ip(), Joi.string().domain()),
    DB_TYPE: Joi.string().valid("mysql", "postgres"),
    DB_DATABASE: Joi.string().required(),
    DB_USERNAME: Joi.string().required(),
    DB_PASSWORD: Joi.string().required(),
    DB_SYNC: Joi.boolean().default(false),
    LOG_ON: Joi.boolean(),
    LOG_LEVEL: Joi.string()
});


@Global()
@Module({
    imports: [
        ScheduleModule.forRoot(),
        ConfigModule.forRoot({
            isGlobal: true,
            envFilePath,
            // https://github.com/nestjs/config/issues/209#issuecomment-625765057
            // load方法需要自己加入验证
            // 解决方法：https://dev.to/rrgt19/ways-to-validate-environment-configuration-in-a-forfeature-config-in-nestjs-2ehp
            load: [
                () => {
                    const values = dotenv.config({ path: ".env" });
                    const { error } = schema.validate(values?.parsed, {
                        // 允许未知的环境变量
                        allowUnknown: true,
                        // 如果有错误，不要立即停止，而是收集所有错误
                        abortEarly: false
                    });
                    if (error) {
                        throw new Error(
                            `Validation failed - Is there an environment variable missing?
                         ${error.message}`
                        );
                    }
                    return values;
                }
            ],
            validationSchema: schema
        }),
        // 服务静态化, 生产环境最好使用 nginx 做资源映射， 可以根据环境配置做区分
        ServeStaticModule.forRootAsync({
            imports: [ConfigModule],
            inject: [ConfigService],
            useFactory: (config: ConfigService) => [{
                rootPath: path.join(__dirname, "../../", "upload"),
                exclude: [`${config.get("API_PREFIX")}`],
                serveRoot: config.get("FILE_SERVE_ROOT"),
                serveStaticOptions: {
                    cacheControl: true
                }
            }] as ServeStaticModuleOptions[]
        }),
        // Redis集成
        // RedisModule.forRootAsync({
        //   useFactory: (configService: ConfigService, logger: LoggerService) => {
        //     const host = configService.get(ConfigEnum.REDIS_HOST);
        //     const port = configService.get(ConfigEnum.REDIS_PORT);
        //     const password = configService.get(ConfigEnum.REDIS_PASSWORD);
        //     const url = password
        //       ? `redis://${password}@${host}:${port}`
        //       : `redis://${host}:${port}`;
        //     return {
        //       config: {
        //         url,
        //         reconnectOnError: (err) => {
        //           logger.error(`Redis Connection error: ${err}`);
        //           return true;
        //         },
        //       },
        //     };
        //   },
        //   inject: [ConfigService, Logger],
        // }),
        TypeOrmModule.forRoot(connectionParams),
        TypeOrmModule.forFeature([Log]),
        UserModule,
        RoleModule,
        AuthModule,
        UserRoleModule,
        SysConfigModule,
        SysDictModule,
        LogModule,
        TasksModule,
        MenuModule,
        RoleMenuModule,
        ApiModule,
        RoleApiModule,
        UserSubuserModule,
        OssModule
    ],
    controllers: [],
    providers: [
        Logger,
        //注册全局过滤器
        {
            provide: APP_FILTER,
            useClass: ExceptionsFilter //全局错误拦截
        },
        {
            provide: APP_FILTER,
            useClass: HttpExceptionFilter//全局http过滤器
        },
        //注册全局守卫
        // {
        //   provide: APP_GUARD,
        //   useClass: AdminGuard,
        // },
        {
            provide: APP_GUARD,
            useClass: JwtAuthGuard
        }
    
    ],
    exports: [Logger]
})
export class AppModule {
}
